// https://leetcode.cn/problems/minimum-genetic-mutation/

// 题干：基因序列可以表示为一条由 8 个字符组成的字符串，其中每个字符都是 'A'、'C'、'G' 和 'T' 之一。
//      假设我们需要调查从基因序列 start 变为 end 所发生的基因变化。一次基因变化就意味着这个基因序列中的一个字符发生了变化。
//      例如，"AACCGGTT" --> "AACCGGTA" 就是一次基因变化。
//      另有一个基因库 bank 记录了所有有效的基因变化，只有基因库中的基因才是有效的基因序列。（变化后的基因必须位于基因库 bank 中）
//      给你两个基因序列 start 和 end ，以及一个基因库 bank ，请你找出并返回能够使 start 变化为 end 所需的最少变化次数。如果无法完成此基因变化，返回 -1 。
//      注意：起始基因序列 start 默认是有效的，但是它并不一定会出现在基因库中

// 示例：输入：start = "AACCGGTT", end = "AACCGGTA", bank = ["AACCGGTA"]
//      输出：1

// 碎语：怎么转化为边权为1的最短路问题
//       能抽象成图论问题，画图即可

#include <bits/stdc++.h>
using namespace std;

class Solution
{
public:
    int minMutation(string startGene, string endGene, vector<string>& bank)
    {
        unordered_set<string> vis; // 存储已经搜查过的状态
        unordered_set<string> hash(bank.begin(), bank.end()); // 存储基因库里面的合法基因
        string change = "ACGT";

        // 特殊情况处理
        if (startGene == endGene) return 0; // 若起始基因就符合题意
        if (!hash.count(endGene)) return -1; // 若目标基因不在基因库里面

        queue<string> q;
        q.push(startGene);
        vis.insert(startGene); // 存储起始基因并标记

        int ret = 0;
        while (q.size()){
            ret++; // 每次BFS拓展便记录一次
            int sz = q.size();

            while (sz--){
                auto t= q.front();
                q.pop();

                for (int i = 0 ; i < 8 ; i++){
                    string tmp = t; // 每个单独改变
                    for (int j = 0 ; j < 4 ; j++){
                        tmp[i] = change[j];
                        if (hash.count(tmp) && !vis.count(tmp)){
                            if (tmp == endGene) return ret;
                            vis.insert(tmp);
                            q.push(tmp);
                        }
                    }
                }
            }
        }

        return -1;
    }
};

int main()
{
    Solution sol;
    string start = "AACCGGTT", end = "AAACGGTA";
    vector<string> bank = {"AACCGGTA","AACCGCTA","AAACGGTA"};

    cout << sol.minMutation(start, end, bank) << endl;

    return 0;
}






